/// 无锁单生产者单消费者FIFO环形缓冲区，具有对内部数据的直接访问

/// 首先，您需要创建环形缓冲区。建议使用HeapRb，但您可以选择其他的。 
/// 在创建环形缓冲区后，可以将其拆分为一对生产者和消费者。
/// 生产者用于向环形缓冲区中插入项，消费者则用于从中移除项。


/// 提供了几种类型的环形缓冲区：
/// LocalRb。仅供单线程使用。
/// SharedRb。可以在多个线程之间共享。它的常用实例：
/// HeapRb。内容存储在动态内存中。推荐在大多数情况下使用。
/// StaticRb。内容可以存储在静态分配的内存中。
/// 您还可以提供自己的通用参数。
/// 
/// 

/// 
/// SharedRb 需要在 CPU 核心之间同步 CPU 缓存。这个同步会有一些开销。
/// 为了避免多次不必要的同步，您可以使用一次操作多个项目的方法（push_slice/push_iter，pop_slice/pop_iter 等），
/// 或者您可以冻结生产者或消费者，然后手动同步线程（请参见 frozen 模块中的项）。
/// 对于单线程使用，推荐使用 LocalRb，因为由于没有 CPU 缓存同步，它稍微快于 SharedRb。

use ringbuf::{traits::*, HeapRb};

#[derive(Debug)]
pub struct RgbFrame {
    pub width: usize,
    pub height: usize,
    pub data: Vec<u8>,
}

fn main() {
    // 创建一个环形缓冲区，容量为 2。
    let rb = HeapRb::<i32>::new(2);
    // 拆分为生产者和消费者。
    let (mut prod, mut cons) = rb.split();
    
    prod.try_push(1).unwrap();
    prod.try_push(2).unwrap();
    
    // prod.try_push(3).unwrap(); // 缓冲区已满，返回 Err。
    assert_eq!(prod.try_push(3), Err(3));
    
    println!("cons.try_pop() = {:?}", cons.try_pop()); //先进先出，pop 1出来
    
    // 上面已经消费一个，所以缓冲区有空间。这里不报错。
    prod.try_push(3).unwrap();
    
    // 再次消费
    println!("cons.try_pop() = {:?}", cons.try_pop()); // 2
    println!("cons.try_pop() = {:?}", cons.try_pop()); // 3
    println!("cons.try_pop() = {:?}", cons.try_pop()); // None 已经消费完毕
    println!("cons.try_pop() = {:?}", cons.try_pop()); // None 已经消费完毕
    println!("cons.try_pop() = {:?}", cons.try_pop()); // None 已经消费完毕

    println!("-------------------------------------------------------------------producer thread struct");
    let rb1 = HeapRb::<RgbFrame>::new(1024);
    let (mut prod, mut cons) = rb1.split();
    std::thread::Builder::new()
        .name("producer".into())
        .spawn(move || {
            for i in 0..1000000 {
                let rgb_frame = RgbFrame {
                    width: 640,
                    height: 480,
                    data: vec![1,2,3],
                };
                match prod.try_push(rgb_frame) {
                    Ok(_) => {}
                    Err(_) => {
                        println!("producer thread: buffer full");
                    }
                }
            }
        }).expect("producer thread error");
    
    let c = std::thread::Builder::new()
        .name("consumer".into())
        .spawn(move || {
            loop {
                match cons.try_pop() {
                    None => {}
                    Some(s) => {
                        println!("consumer thread: {:?}", s);
                    }
                }
            }
        }).expect("consumer thread error");
    
    c.join().expect("consumer thread error");
}